#include "../LMCommon.h"
#include "LMMasterProxy.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include "../LMContext.h"
#include "../proto/workitem.pb.h"

LMMasterProxy::LMMasterProxy(boost::shared_ptr<LMContext> context)
	:_context(context)
{
}


LMMasterProxy::~LMMasterProxy(void)
{
}

void LMMasterProxy::run()
{
	std::cout << "Master proxy running..." << std::endl;
	std::cout << "Start Loop..." << std::endl;

	for(;;)
	{
		if(!_socket || !(_socket->is_open()))
		{
			// Connect
			boost::asio::ip::tcp::resolver resolver(_ioSrv); //resolve dns
			boost::asio::ip::tcp::resolver::query query(_context->PoolIp(), boost::lexical_cast<std::string>(_context->PoolPort()));
			boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
			boost::asio::ip::tcp::resolver::iterator end;  
			boost::asio::ip::tcp::endpoint endpoint;
			boost::system::error_code error_socket = boost::asio::error::host_not_found;
			while (error_socket && endpoint_iterator != end)  
			{  
				endpoint = *endpoint_iterator ; 
				std::cout << "connecting to " << endpoint << std::endl;
				_socket.reset(new boost::asio::ip::tcp::socket(_ioSrv));
				_socket->connect(endpoint, error_socket);  
				endpoint_iterator++ ;  
			}

			boost::asio::ip::tcp::no_delay nd_option(true);
			boost::asio::socket_base::keep_alive ka_option(true);
			_socket->set_option(nd_option);
			_socket->set_option(ka_option);
			boost::asio::socket_base::non_blocking_io command(true);
			_socket->io_control(command);

			if (error_socket) {
				std::cout << error_socket << std::endl;
				Sleep(10000);
				continue;
			}
		}

		// Receive size
		std::cout << "Prepare receive size." << std::endl;
		int recvd = 0;
		int proto_size = 0;
		boost::system::error_code ec;
		recvd = _socket->read_some(boost::asio::buffer((char*)(&proto_size), 4), ec);
		if(ec == boost::asio::error::would_block)
		{
			Sleep(10);
			continue;
		}
		std::cout << "Read header got: " << recvd << " bytes." << std::endl;

		boost::scoped_array<char> proto_buf(new char[proto_size]);
		recvd = 0;
		// Get Body
		while(recvd < proto_size)
			recvd += _socket->read_some(boost::asio::buffer(proto_buf.get() + recvd, proto_size - recvd));

		ProtoXptBlockWorkInfo proto_bwi;
		proto_bwi.ParseFromArray(proto_buf.get(), proto_size);
		std::cout << "ProtoXptBlockWorkInfo: " << proto_bwi.ShortDebugString() << std::endl;

		// Convert
		struct  
		{
			CRITICAL_SECTION cs_work;
			uint32	algorithm;
			// block data
			uint32	version;
			uint32	height;
			uint32	nBits;
			uint32	timeBias;
			uint8	merkleRootOriginal[32]; // used to identify work
			uint8	prevBlockHash[32];
			uint8	target[32];
			uint8	targetShare[32];
			uint32  targetCompact;
			uint32  shareTargetCompact;
			// extra nonce info
			uint8	coinBase1[1024];
			uint8	coinBase2[1024];
			uint16	coinBase1Size;
			uint16	coinBase2Size;
			// transaction hashes
			uint8	txHash[32*MAX_TRANSACTIONS];
			uint32	txHashCount;
		}workDataSource;
	}
}

void LMMasterProxy::findShare()
{

}
